﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApp2
{
    public class PolandNotation
    {
        /// <summary>
        /// 计算
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static T Calculate<T>(string expression)
        {
            //将中缀表达式转换成后缀表达式
            List<string> suffixExpression = PolandNotation.ParseSuffixExpression<T>(expression);

            //创建栈
            Stack<string> stack = new Stack<string>();

            //循环遍历
            suffixExpression.ForEach(item =>
            {
                string regex = GetRegex<T>();
                if (Regex.IsMatch(item, regex))//"\\d+"
                {
                    //如果是数字直接入栈
                    stack.Push(item);
                }
                //如果是操作符
                else
                {
                    //出栈两个数字，并运算，再入栈
                    dynamic num1 = (T)Convert.ChangeType(stack.Pop(), typeof(T));

                    dynamic num2 = (T)Convert.ChangeType(stack.Pop(), typeof(T));

                    T result = default(T);

                    if (item.Equals("+"))
                    {
                        result = num2 + num1;
                    }
                    else if (item.Equals("*"))
                    {
                        result = num2 * num1;
                    }
                    else if (item.Equals("/"))
                    {
                        result = num2 / num1;
                    }
                    else if (item.Equals("-"))
                    {
                        result = num2 - num1;
                    }
                    else
                    {
                        throw new Exception("无法识别符号");
                    }

                    stack.Push("" + result);
                }
            });

            //最后把stack中数据返回
            return (T)Convert.ChangeType(stack.Pop(), typeof(T));
        }

        /// <summary>
        /// 字符串转中缀表达式的List
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        private static List<string> ToInfixExpression(string expression)
        {
            List<string> list = new List<string>();

            int index = 0;

            string str = "";

            do
            {

                //48-57ASCII码代表的是0-9 如果不是0-9直接入链表
                if (expression[index] < 48 || expression[index] > 57)//ascii编码
                {
                    list.Add("" + expression[index]);

                    index++;
                }
                else
                {
                    str = "";

                    //多位数判断
                    while (index < expression.Length && (expression[index] >= 48 && expression[index] <= 57 || expression[index] == 46))
                    {

                        str += expression[index];

                        index++;
                    }

                    list.Add(str);
                }

            } while (index < expression.Length);

            return list;
        }

        /// <summary>
        /// 中缀转后缀
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        private static List<string> ParseSuffixExpression<T>(string expression)
        {
            List<string> expressionList = ToInfixExpression(expression);

            //存储中间结果
            List<string> list = new List<string>();
            //符号栈
            Stack<string> stack = new Stack<string>();

            foreach (var item in expressionList)
            {
                //多位数判断 如果是数字直接加入list
                var regex = GetRegex<T>();
                if (Regex.IsMatch(item, regex))//"\\d+"
                {
                    list.Add(item);
                }
                //如果是左括号，直接入符号栈
                else if (item.Equals("("))
                {
                    stack.Push(item);
                }
                //如果是右括号
                else if (item.Equals(")"))
                {
                    //依次弹出stack栈顶的运算符，并存入list,直到遇到左括号为止
                    while (!stack.Peek().Equals("("))
                    {
                        list.Add(stack.Pop());
                    }
                    //将(也出栈
                    stack.Pop();
                }
                //如果是*/+-
                else
                {
                    //循环判断item的优先级小于或者等于stack栈顶运算符，将stack栈顶的运算符出栈并加入到list中
                    while (stack.Count != 0 && Operation.GetValue(stack.Peek()) >= Operation.GetValue(item))
                    {
                        list.Add(stack.Pop());
                    }
                    //将item入栈
                    stack.Push(item);
                }
            }

            //将stack剩余的运算符依次入list
            while (stack.Count != 0)
            {
                list.Add(stack.Pop());
            }

            return list;
        }

        private static string GetRegex<T>()
        {
            string regex = "\\d+";
            Type t = typeof(T);
            if (t == typeof(Int16) || t == typeof(Int32) || t == typeof(Int64))
            {
                regex = "\\d+";
            }
            else if (t == typeof(float) || t == typeof(double) || t == typeof(decimal))
            {
                regex = "(\\d+\\.\\d+|\\d+)";
            }
            return regex;
        }
    }
    public class Operation
    {
        private static int ADD = 1;
        private static int SUB = 1;
        private static int MUL = 2;
        private static int DIV = 2;

        public static int GetValue(string operation)
        {
            int result = 0;

            switch (operation)
            {
                case "+":
                    result = ADD;
                    break;
                case "-":
                    result = SUB;
                    break;
                case "*":
                    result = MUL;
                    break;
                case "/":
                    result = DIV;
                    break;
                default:
                    // Console.WriteLine("不存在该运算符");
                    break;
            }

            return result;
        }
    }
}
